/*
 * ****************************************************************************
 * Copyright: 2020-2030, YZChain Tech. Co., Ltd.
 * File name:
 * Description:
 * Author: Dc luo
 * Version: v1.0
 * Date: $DATE
 * History:
 * ***************************************************************************
 */

package com.srp.blockchain.bcos.service.impl;

import com.srp.blockchain.bcos.dto.*;
import com.srp.blockchain.bcos.service.BcosService;
import com.srp.common.utils.Dto2Entity;
import lombok.extern.slf4j.Slf4j;
import org.fisco.bcos.channel.client.P12Manager;
import org.fisco.bcos.web3j.crypto.Credentials;
import org.fisco.bcos.web3j.crypto.ECKeyPair;
import org.fisco.bcos.web3j.crypto.gm.GenCredential;
import org.fisco.bcos.web3j.protocol.Web3j;
import org.fisco.bcos.web3j.protocol.core.methods.response.BcosBlock;
import org.fisco.bcos.web3j.protocol.core.methods.response.Transaction;
import org.fisco.bcos.web3j.protocol.core.methods.response.TransactionReceipt;
import org.fisco.bcos.web3j.tx.txdecode.TransactionDecoder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.spec.InvalidKeySpecException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


@Slf4j
@Service
public class BcosServiceImpl implements BcosService {

    @Autowired
    private Web3j web3j;
    // TODO  解析交易输入输出
    private TransactionDecoder decoder;

    private String p12File;
    private String password;

    /**
     * 获取链状态信息
     *
     * @return
     */
    @Override
    public ChainStatusDTO getChainStates() {

        String txNumber;
        String blockHeight;

        try {
            txNumber = web3j.getTotalTransactionCount()
                    .send()
                    .getTotalTransactionCount()
                    .getTxSum()
                    .toString();

        } catch (Exception e) {
            txNumber = "0";
            log.error("web3j.getTotalTransactionCount error", e);
        }
        try {
            blockHeight = web3j.getBlockNumber()
                    .send()
                    .getBlockNumber()
                    .toString();
        } catch (Exception e) {
            blockHeight = "0";
            log.error("web3j.getBlockNumber error", e);
        }
        return new ChainStatusDTO(0, blockHeight, txNumber, 0, 0);

    }

    /**
     * 根据交易哈希查询
     *
     * @return
     * @throws
     */
    @Override
    public TransactionDTO queryTransByHash(String hash) {
        Transaction transaction = new Transaction();
        TransactionReceipt receipt = new TransactionReceipt();
        try {
            transaction = web3j.getTransactionByHash(hash).send().getResult();
        } catch (Exception e) {
            log.error("getTransactionByHash failed:", e);
            return null;
        }
        try {
            receipt = web3j.getTransactionReceipt(hash).send().getResult();
        } catch (Exception e) {
            log.error("getTransactionReceipt", e);
            return null;
        }
        if (Objects.isNull(transaction)  || Objects.isNull(receipt)) {
            return null;
        }
        log.info("tx info:{}", transaction.toString());
        log.info("tx receipt info:{}", receipt.toString());
        TxInfoDTO infoDTO = new TxInfoDTO();
        TxReceiptDTO receiptDTO = new TxReceiptDTO();
        try {
            Dto2Entity.translate(transaction, infoDTO);
            Dto2Entity.translate(receipt, receiptDTO);
        } catch (Exception e) {
            log.error("Dto2Entity failed", e);
            return null;
        }
        log.info("tx translated info:{}", infoDTO.toString());
        log.info("tx translate info:{}", receiptDTO.toString());
        return new TransactionDTO(infoDTO, receiptDTO);

    }


    /**
     * 根据哈希查询区块信息
     *
     * @return
     * @Param hash 区块哈希
     */
    @Override
    public BlockInfoDTO queryBlockByHash(String hash) {

        List<String> transactionList = new ArrayList<>();
        BlockInfoDTO blockInfoDTO = new BlockInfoDTO();
        BcosBlock.Block blockInfo;
        try {
            blockInfo = web3j.getBlockByHash(hash, false)
                    .send()
                    .getBlock();
        } catch (Exception e) {
            log.error("Get block info failed:", e);
            return null;
        }
        log.info("Block info:{}", blockInfo.toString());
        for (BcosBlock.TransactionResult tx : blockInfo.getTransactions()) {
            transactionList.add((String) tx.get());
        }
        Dto2Entity.translate(blockInfo, blockInfoDTO);
        blockInfoDTO.setTransactions(transactionList);
        log.info("Block translated info:{}", blockInfoDTO.toString());

        return blockInfoDTO;
    }


    /**
     * 密钥加载
     */
    // load p12 account file
    public Credentials loadP12AccountByName(String CredentialName)
            throws KeyStoreException, NoSuchAlgorithmException, CertificateException, IOException,
            NoSuchProviderException, InvalidKeySpecException, UnrecoverableKeyException {
        log.info("p12 accounts : {}", CredentialName);
        P12Manager p12Manager = new P12Manager();
        p12Manager.setP12File("classpath:" + CredentialName);
        p12Manager.setPassword("123456");
        p12Manager.load();
        ECKeyPair keyPair = p12Manager.getECKeyPair();
        Credentials credentials = GenCredential.create(keyPair.getPrivateKey().toString(16));
        System.out.println(credentials.getAddress());
        return credentials;
    }





}
